package xyz.erupt.flow.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.model.bpmn.Bpmn;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xyz.erupt.core.exception.EruptApiErrorTip;
import xyz.erupt.flow.bean.entity.OaWorkFlowDefinition;
import xyz.erupt.flow.bean.entity.node.OaProcessNode;
import xyz.erupt.flow.core.engine.WorkFlowBuilder;
import xyz.erupt.flow.data.dto.DTO_OaWorkFlowDefinition;
import xyz.erupt.flow.data.mapper.OaWorkFlowDefinitionMapper;
import xyz.erupt.flow.repository.OaWorkFlowDefinitionRepository;
import xyz.erupt.flow.repository.OaWorkFlowGroupRepository;
import xyz.erupt.flow.service.WorkFlowDefinitionService;
import xyz.erupt.flow.utils.ProcessKeyGenerator;
import xyz.erupt.flow.utils.WorkFlowUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @description:
 * @className: WorkFlowDefinitionServiceImpl
 * @author: PP
 * @date: 2024/10/19 22:54
 * @Version: 1.0
 */
@Service
public class WorkFlowDefinitionServiceImpl implements WorkFlowDefinitionService {
    @Autowired
    private OaWorkFlowDefinitionRepository oaWorkFlowDefinitionRepository;
    @Autowired
    private OaWorkFlowGroupRepository oaWorkFlowGroupRepository;
    @Autowired
    private WorkFlowBuilder workFlowBuilder;
    @Autowired
    private RepositoryService repositoryService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(DTO_OaWorkFlowDefinition entity) {
        OaWorkFlowDefinition oaWorkFlowDefinition = oaWorkFlowDefinitionRepository.LastVersion(entity.getProcessKey());
        OaWorkFlowDefinition workFlowDefinition = OaWorkFlowDefinitionMapper.INSTANCE.dtoTo(entity);
        if (oaWorkFlowDefinition == null) {
            throw new EruptApiErrorTip("不存在该流程定义！");
        }
        BeanUtil.copyProperties(workFlowDefinition, oaWorkFlowDefinition, CopyOptions.create().setIgnoreNullValue(true).setIgnoreProperties("id","updateTime","isStop"));
        oaWorkFlowDefinition.setUpdateTime(new Date(System.currentTimeMillis()));//设置更新时间
        oaWorkFlowDefinition.setVersion(oaWorkFlowDefinitionRepository.LastVersionNum(entity.getProcessKey())+1);
        OaWorkFlowDefinition save = oaWorkFlowDefinitionRepository.save(oaWorkFlowDefinition);
        //部署流程
        workFlowBuilder.build(save);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void create(DTO_OaWorkFlowDefinition workFlowDefinition) {
        OaWorkFlowDefinition oaWorkFlowDefinition = OaWorkFlowDefinitionMapper.INSTANCE.dtoTo(workFlowDefinition);
        OaWorkFlowDefinition build = OaWorkFlowDefinition.builder()
                .updateTime(new Date(System.currentTimeMillis()))
                .version(1L)
                .processKey(ProcessKeyGenerator.generateProcessKey())//生成流程键
                .build();
        BeanUtil.copyProperties(oaWorkFlowDefinition, build, CopyOptions.create().setIgnoreNullValue(true).setIgnoreProperties("id","processKey"));
        OaWorkFlowDefinition save = oaWorkFlowDefinitionRepository.save(build);
        //部署流程
        workFlowBuilder.build(save);
    }


    @Override
    public List<OaWorkFlowDefinition> listByGroupId(Long groupId, String keywords) {
        return oaWorkFlowDefinitionRepository.listByGroupId(groupId,keywords);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void DefSort(List<Long> defIds) {
        List<OaWorkFlowDefinition> updateList = new ArrayList<>();
        for (int i1 = 0;i1<defIds.size();i1++){
            OaWorkFlowDefinition data = oaWorkFlowDefinitionRepository.findById(defIds.get(i1)).orElse(null);
            data.setSort(i1);
            updateList.add(data);
        }
        oaWorkFlowDefinitionRepository.saveAll(updateList);
    }

    @Override
    public void StopDef(String processKey) {
        List<OaWorkFlowDefinition> oaWorkFlowDefinitions = oaWorkFlowDefinitionRepository.LastVersions(processKey);
        oaWorkFlowDefinitions.forEach(s->{
            s.setStop(true);//设置停用
            s.setWorkFlowGroup(null);//设置空分组
        });
        oaWorkFlowDefinitionRepository.saveAll(oaWorkFlowDefinitions);
    }

    @Override
    public void StartDef(String processKey) {
        List<OaWorkFlowDefinition> oaWorkFlowDefinitions = oaWorkFlowDefinitionRepository.LastVersions(processKey);
        oaWorkFlowDefinitions.forEach(s->{
            s.setStop(false);//设置启用
        });
        oaWorkFlowDefinitionRepository.saveAll(oaWorkFlowDefinitions);
    }

    @Override
    public void removeByProcessKey(String processKey) {
        List<OaWorkFlowDefinition> oaWorkFlowDefinitions = oaWorkFlowDefinitionRepository.LastVersions(processKey);
        if(oaWorkFlowDefinitions!=null&&oaWorkFlowDefinitions.size()>0){
            oaWorkFlowDefinitionRepository.deleteAllById(oaWorkFlowDefinitions.stream().map(s->s.getId()).collect(Collectors.toList()));
        }
    }


    @Override
    public OaWorkFlowDefinition getByProcessKey(String processKey) {
        return oaWorkFlowDefinitionRepository.LastVersion(processKey);
    }

    @Override
    public OaWorkFlowDefinition getById(Long id) {
        return oaWorkFlowDefinitionRepository.findById(id).orElseThrow(()->new EruptApiErrorTip("无流程定义数据"));
    }

    /**
     * 预览时间轴(bpmn流程)
     */
    @Override
    public String preview(String processKey){
        OaWorkFlowDefinition workFlowDefinition = getByProcessKey(processKey);
        String key = WorkFlowUtils.workFlowDefinitionIdToKey(workFlowDefinition.getId());
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(key)
                .latestVersion()
                .singleResult();
        BpmnModelInstance bpmnModelInstance = repositoryService.getBpmnModelInstance(processDefinition.getId());
        return Bpmn.convertToString(bpmnModelInstance);
    }



}
